package org.chen.spring.core.factory;

import org.chen.spring.core.annotation.Scope;

import java.beans.Introspector;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.*;

/**
 * 扫描Bean接口
 *
 * @author Chen
 * @since 2023/6/7 20:47
 */
public abstract class ScanBean {

    protected static Map<String, BeanDefinition> beanDefinitionMap = BeanFactory.getBeanDefinitionMap();

    private static final Set<String> componentScan = new HashSet<>();

    public ScanBean(List<String> componentScan) {
        ScanBean.componentScan.addAll(componentScan);
    }

    public ScanBean(String componentScan) {
        ScanBean.componentScan.add(componentScan);
    }

    public void scan(List<String> componentScan) {
        ScanBean.componentScan.addAll(componentScan);
        for (String scan : ScanBean.componentScan) {
            String path = scan.replace(".", "/");
            ClassLoader classLoader = BeanFactory.class.getClassLoader();
            URL contextResourceUrl = classLoader.getResource(path);
            assert contextResourceUrl != null;
            File beanFile = new File(contextResourceUrl.getFile());
            scanBean(path, beanFile);
        }
    }

    private void scanBean(String path, File beanFile) {
        for (File file : Objects.requireNonNull(beanFile.listFiles())) {
            if (file.isDirectory()) {
                scanBean(path, file);
            }
            String beanPath = file.getAbsolutePath();
            if (beanPath.endsWith(".class")) {
                //截取包名前缀名
                String prefix = path.substring(0, path.indexOf("/"));
                // com\chen\service\UserService
                String className = beanPath.substring(beanPath.indexOf(prefix), beanPath.indexOf(".class"));
                className = className.replace("\\", ".");
                try {
                    Class<?> bean = Class.forName(className);
                    if (bean.isAnnotation()) {
                        continue;
                    }
                    for (Annotation annotation : bean.getAnnotations()) {
                        assembleBeanDefinition(bean, annotation);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    ;

    protected abstract void assembleBeanDefinition(Class<?> bean, Annotation annotation);


    protected void addBeanDefinition(Class<?> interfaceAchieveClass) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setType(interfaceAchieveClass);
        beanDefinition.setScope("singleton");
        if (interfaceAchieveClass.isAnnotationPresent(Scope.class)) {
            beanDefinition.setScope(interfaceAchieveClass.getAnnotation(Scope.class).value());
        }
        beanDefinitionMap.put(Introspector.decapitalize(interfaceAchieveClass.getSimpleName()), beanDefinition);
    }

    /**
     * 获取所有接口的实现类
     */
    public static List<Class<?>> getAllInterfaceAchieveClass(Class<?> clazz) {
        ArrayList<Class<?>> list = new ArrayList<>();
        //判断是否是接口
        if (clazz.isInterface()) {
            try {
                ArrayList<Class<?>> allClass = getAllClassByPath(clazz.getPackage().getName());
                /*
                  循环判断路径下的所有类是否实现了指定的接口
                  并且排除接口类自己
                 */
                for (Class<?> aClass : allClass) {
                    //排除抽象类
                    if (Modifier.isAbstract(aClass.getModifiers())) {
                        continue;
                    }
                    //判断是不是同一个接口
                    if (clazz.isAssignableFrom(aClass)) {
                        if (!clazz.equals(aClass)) {
                            list.add(aClass);
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        }
        return list;
    }

    /**
     * 从指定路径下获取所有类
     */
    public static ArrayList<Class<?>> getAllClassByPath(String packagename) {
        ArrayList<Class<?>> list = new ArrayList<>();
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packagename.replace('.', '/');
        try {
            ArrayList<File> fileList = new ArrayList<>();
            Enumeration<URL> enumeration = classLoader.getResources(path);
            while (enumeration.hasMoreElements()) {
                URL url = enumeration.nextElement();
                fileList.add(new File(url.getFile()));
            }
            for (File file : fileList) {
                list.addAll(findClass(file, packagename));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 如果file是文件夹，则递归调用findClass方法，或者文件夹下的类
     * 如果file本身是类文件，则加入list中进行保存，并返回
     */
    private static ArrayList<Class<?>> findClass(File file, String packagename) {
        ArrayList<Class<?>> list = new ArrayList<>();
        if (!file.exists()) {
            return list;
        }
        File[] files = file.listFiles();
        assert files != null;
        for (File file2 : files) {
            if (file2.isDirectory()) {
                assert !file2.getName().contains(".");//添加断言用于判断
                ArrayList<Class<?>> arrayList = findClass(file2, packagename + "." + file2.getName());
                list.addAll(arrayList);
            } else if (file2.getName().endsWith(".class")) {
                try {
                    //保存的类文件不需要后缀.class
                    list.add(Class.forName(packagename + '.' + file2.getName().substring(0,
                            file2.getName().length() - 6)));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }

}
